package com.gitee.feizns.quickstart.jackson;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.gitee.feizns.quickstart.jackson.filter.IgnorePrimitiveSimpleBeanPropertyFilter;
import com.gitee.feizns.quickstart.jackson.module.Java8TimeDeserializer;
import com.gitee.feizns.quickstart.jackson.module.Java8TimeSerializer;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Year;
import java.time.YearMonth;
import java.util.TimeZone;

/**
 * 快速入门对象映射器
 * @author feizns
 * @since 2023/04/02
 */
public class QuickstartObjectMapper extends ObjectMapper {

    /**
     * 忽略基础类型
     */
    public static final String IGNORE_PRIMITIVE_FILTER_NAME = "ignore-primitive";

    /**
     * 快速入门对象映射器
     */
    public QuickstartObjectMapper() {
        super();
        //使用自己默认配置
        applyDefaultConfigure(this);
        //注册java8
        registerJava8TimeModule();
    }

    /**
     * 使用自己默认配置
     * @param objectMapper 对象映射器
     */
    public static void applyDefaultConfigure(ObjectMapper objectMapper) {
        //**************序列化相关
        //所有非null的字段才序列化
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        //在空对象的序列化时不报错（直接序列化为空对象）
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        //报错时不需要引用链
        objectMapper.configure(SerializationFeature.WRAP_EXCEPTIONS, false);

        //**************反序列化相关
        //报错时不需要引用链
        objectMapper.configure(DeserializationFeature.WRAP_EXCEPTIONS, false);
        //有对象中不存在的字段时也允许反序列化
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //将所有数字都为long
        objectMapper.configure(DeserializationFeature.USE_LONG_FOR_INTS, true);
        //允许单引号
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        //允许单个对象反序列化为数组
        objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
//        //允许空字符串反序列化为空对象
//        objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
        //允许单个值的数组反序列化为对象
        objectMapper.configure(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS, true);
        //设置时间
        objectMapper.setTimeZone(TimeZone.getDefault());
        //注册过滤基础类型字段的过滤器
        SimpleFilterProvider filter = new SimpleFilterProvider();
        filter.addFilter(IGNORE_PRIMITIVE_FILTER_NAME, new IgnorePrimitiveSimpleBeanPropertyFilter());
        objectMapper.setFilterProvider(filter);
    }

    /**
     * 注册 Java8 时间模块
     */
    public void registerJava8TimeModule() {
        registerModule(java8TimeModule());
    }

    /**
     * 注册 Java8 时间模块
     * @return {@link JavaTimeModule }
     */
    public static JavaTimeModule java8TimeModule() {
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addDeserializer(Year.class, new Java8TimeDeserializer<>(Year.class));
        javaTimeModule.addDeserializer(YearMonth.class, new Java8TimeDeserializer<>(YearMonth.class));
        javaTimeModule.addDeserializer(LocalDate.class, new Java8TimeDeserializer<>(LocalDate.class));
        javaTimeModule.addDeserializer(LocalTime.class, new Java8TimeDeserializer<>(LocalTime.class));
        javaTimeModule.addDeserializer(LocalDateTime.class, new Java8TimeDeserializer<>(LocalDateTime.class));
        javaTimeModule.addSerializer(Year.class, new Java8TimeSerializer("yyyy"));
        javaTimeModule.addSerializer(YearMonth.class, new Java8TimeSerializer("yyyy-MM"));
        javaTimeModule.addSerializer(LocalDate.class, new Java8TimeSerializer("yyyy-MM-dd"));
        javaTimeModule.addSerializer(LocalTime.class, new Java8TimeSerializer("HH:mm:ss.SSS"));
        javaTimeModule.addSerializer(LocalDateTime.class, new Java8TimeSerializer("yyyy-MM-dd'T'HH:mm:ss.SSS"));
        return javaTimeModule;
    }

}
